package com.iflytek.jcy.supervise.clue.service.impl;

import com.iflytek.jcy.supervise.clue.common.enums.ResultEnum;
import com.iflytek.jcy.supervise.clue.common.enums.WeightEnum;
import com.iflytek.jcy.supervise.clue.common.exception.BaseException;
import com.iflytek.jcy.supervise.clue.common.pojo.CommonResponse;
import com.iflytek.jcy.supervise.clue.common.pojo.MongoPageResult;
import com.iflytek.jcy.supervise.clue.common.util.FileUtils;
import com.iflytek.jcy.supervise.clue.component.httpinterface.ModelHttpInterface;
import com.iflytek.jcy.supervise.clue.component.httpinterface.modelResponse.Checkpointlist;
import com.iflytek.jcy.supervise.clue.component.httpinterface.modelResponse.ModelInfo;
import com.iflytek.jcy.supervise.clue.component.httpinterface.modelResponse.Reportfieldlist;
import com.iflytek.jcy.supervise.clue.component.httpinterface.result.OutModelResponse;
import com.iflytek.jcy.supervise.clue.dto.QueryClueDTO;
import com.iflytek.jcy.supervise.clue.dto.QueryClueDeatilDTO;
import com.iflytek.jcy.supervise.clue.dto.QueryClueDetailDTO;
import com.iflytek.jcy.supervise.clue.dto.QueryClueResultDTO;
import com.iflytek.jcy.supervise.clue.dto.QueryPointDTO;
import com.iflytek.jcy.supervise.clue.dto.inquisitor.ManageDTO;
import com.iflytek.jcy.supervise.clue.dto.response.InfoPageDTO;
import com.iflytek.jcy.supervise.clue.dto.response.ManageTaskDetailDTO;
import com.iflytek.jcy.supervise.clue.dto.response.TaskDetailDTO;
import com.iflytek.jcy.supervise.clue.entity.*;
import com.iflytek.jcy.supervise.clue.mapper.*;
import com.iflytek.jcy.supervise.clue.service.*;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 线索表 服务实现类
 * </p>
 *
 * @author dgyu
 * @since 2022-10-20 */
@Service
public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements IClueService {

	private static final Logger	   logger = LoggerFactory.getLogger(ClueServiceImpl.class);

	@Autowired
	private ClueMapper			   clueMapper;
	@Autowired
	private ITaskDetailService	   iTaskDetailService;
	@Autowired
	private TaskDetailMapper	   taskDetailMapper;
	@Autowired
	private TaskService			   taskService;
	@Resource
	private ModelHttpInterface	   modelHttpInterface;
	@Resource
	private MongoService		   mongoService;
	@Resource
	private TaskLogMapper		   taskLogMapper;
	@Resource
	private IClueCollectionService iClueCollectionService;
	@Resource
	private ClueCollectionMapper   clueCollectionMapper;
	@Resource
	private ICluePushService	   iCluePushService;
	@Resource
	private CluePushMapper		   cluePushMapper;
	@Resource
	private TaskMapper			   taskMapper;

	@Override
	public IPage<Clue> list(QueryClueDTO queryClueDTO) {
		Page<Clue> page = new Page<>(queryClueDTO.getPageNo(), queryClueDTO.getPageSize());
		LambdaQueryWrapper<Clue> wrapper = new LambdaQueryWrapper<>();
		wrapper.isNotNull(Clue::getClueNum).gt(Clue::getClueNum,0);
		if (queryClueDTO.getModelId() != null && queryClueDTO.getModelId() > 0) {
			wrapper.eq(Clue::getModelId, queryClueDTO.getModelId());
		}
		if (queryClueDTO.getDatasetId() != null && queryClueDTO.getDatasetId() > 0) {
			wrapper.eq(Clue::getDatasetId, queryClueDTO.getDatasetId());
		}
		if (queryClueDTO.getStartTime() != null) {
			wrapper.ge(Clue::getCreateTime, queryClueDTO.getStartTime());
		}
		if (queryClueDTO.getEndTime() != null) {
			wrapper.le(Clue::getCreateTime, queryClueDTO.getEndTime());
		}
		wrapper.orderByDesc(Clue::getCreateTime);
		IPage<Clue> pageClue = this.baseMapper.selectPage(page, wrapper);
		return pageClue;
	}

	private void writeData2Excel(XSSFWorkbook workbook, Sheet sheet, List<TaskDetailDTO> list, Clue clue) {
		XSSFCellStyle style = this.createStyle(workbook);
		workbook.setSheetName(0, "线索列表");
		Row row = sheet.getRow(1);
		if (row == null) {
			row = sheet.createRow(1);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		for (int i = 0; i < list.size(); i++) {
			TaskDetailDTO vo = list.get(i);
			Row other = sheet.createRow(i + 1);
			createRowAndCell(vo.getSupervisionObject(), other, cell, 0, style);
			createRowAndCell(vo.getSupervisionObjectName(), other, cell, 1, style);
			createRowAndCell(vo.getSupervisionPointName(), other, cell, 2, style);
			createRowAndCell(vo.getSupervisionPointContent(), other, cell, 3, style);
			//修复缺陷JZPDTZFGJJ-437
			createRowAndCell(WeightEnum.getValue(vo.getWeight()), other, cell, 4, style);
			logger.debug("已经导出数据:{}条", (i + 1));
		}
		// 获取监督点
		List<Checkpointlist> points = this.getPoints(clue.getTaskId());
		if (CollectionUtils.isEmpty(points)) {
			return;
		}
		// 数据按照监督点id分组
		Map<Integer, List<TaskDetailDTO>> map = list.stream().collect(Collectors.groupingBy(TaskDetailDTO::getSupervisionPointId));
		// 写入监督点sheet
		for (Checkpointlist point : points) {
			List<TaskDetailDTO> data = map.getOrDefault(point.getId(), new ArrayList<>());
			this.writeSupevisePonits(workbook, point, data, clue);
		}
	}

	// 分监督点写入数据
	private void writeSupevisePonits(XSSFWorkbook workbook, Checkpointlist point, List<TaskDetailDTO> data, Clue clue) {
		XSSFCellStyle style = this.createStyle(workbook);
		XSSFSheet sheet = workbook.createSheet(point.getName());
		Row row = sheet.getRow(0);
		if (row == null) {
			row = sheet.createRow(0);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		// 表头=监督对象+监督对象名称列+报告字段
		LinkedHashSet<String> fileds = new LinkedHashSet<String>(Lists.newArrayList("监督对象", "监督对象名称"));
		List<String> pointFieldList = point.getReportfieldlist().stream().map(Reportfieldlist::getName).collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(pointFieldList)) {
			fileds.addAll(pointFieldList);
		}
		// 根据taskLogId pointId获取Mongo数据
		QueryClueDetailDTO queryClueDetailDTO = new QueryClueDetailDTO(1, Integer.MAX_VALUE, clue.getTaskLogId(), point.getId());
		MongoPageResult<InfoPageDTO> mongoPageResult = this.mongoService.info(queryClueDetailDTO);
		if (mongoPageResult.getTotal() == null || mongoPageResult.getTotal() <= 0L) {
			// 写入第一行表头
			Iterator<String> i = fileds.iterator();
			int index = 0;
			while (i.hasNext()) {
				createRowAndCell(i.next(), row, cell, index, style);
				index++;
			}
			logger.info("监督点:{}下没有数据，跳过", point.getName());
			return;
		}
		List<InfoPageDTO> mongoDataList = mongoPageResult.getData();
		Set<String> reportFieldList = mongoDataList.get(0).getMap().keySet();
		if (CollectionUtils.isNotEmpty(reportFieldList)) {
			fileds.addAll(reportFieldList);
		}
		// 写入第一行表头
		Iterator<String> ii = fileds.iterator();
		int index1 = 0;
		while (ii.hasNext()) {
			createRowAndCell(ii.next(), row, cell, index1, style);
			index1++;
		}
		// 写入数据
		for (int i = 0; i < mongoDataList.size(); i++) {
			InfoPageDTO infoPageDTO = mongoDataList.get(i);
			Map<String, String> map = infoPageDTO.getMap();
			Set<String> keySet = map.keySet();
			Row other = sheet.createRow(i + 1);
			createRowAndCell(infoPageDTO.getReportObject(), other, cell, 0, style);
			createRowAndCell(infoPageDTO.getReportObjectName(), other, cell, 1, style);
			// 从第三列开始写入动态字段
			if (CollectionUtils.isNotEmpty(reportFieldList)) {
				int index = 0;
				for (String key : keySet) {
					createRowAndCell(map.get(key), other, cell, (index + 2), style);
					index++;
				}
			}
			logger.debug("监督点pointName:{}已经写入数据:{}条", point.getName(), (i + 1));
		}
	}

	/** 根据当前row行，来创建index标记的列数,并赋值数据 */
	private void createRowAndCell(Object obj, Row row, Cell cell, int index, XSSFCellStyle alignStyle) {
		cell = row.getCell(index);
		if (cell == null) {
			cell = row.createCell(index);
			cell.setCellStyle(alignStyle);
		}
		if (obj != null) {
			if (obj instanceof Double) {
				cell.setCellValue((Double) obj);
			}
			else if (obj instanceof String) {
				cell.setCellValue((String) obj);
			}
			else if (obj instanceof Boolean) {
				cell.setCellValue((Boolean) obj);
			}
			else if (obj instanceof Long) {
				cell.setCellValue((Long) obj);
			}
			else if (obj instanceof Integer) {
				cell.setCellValue((Integer) obj);
			}
			else if (obj instanceof Float) {
				cell.setCellValue((Float) obj);
			}
			else if (obj instanceof Short) {
				cell.setCellValue((Short) obj);
			}
			else {
				cell.setCellValue(obj + "");
			}
		}
		else
			cell.setCellValue("");
		cell.setCellStyle(alignStyle);
	}

	@Override
	public void export1(Integer clueId, HttpServletResponse response) throws Exception {
		QueryClueResultDTO queryClueResultDTO = new QueryClueResultDTO(1, Integer.MAX_VALUE, clueId);
		IPage<TaskDetailDTO> page = this.iTaskDetailService.listResult(queryClueResultDTO);
		List<TaskDetailDTO> list = page.getRecords();
		// 读取EXCEL模板
		InputStream in = FileUtils.getModel("（线索管理-线索列表-线索管理列表）任务名称（范例：减刑假释长春第一批数据20221020.1022）.xlsx");
		// 复制模板 写入数据
		File tempModel = FileUtils.copyModel(in);
		XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempModel));
		Sheet sheet = wb.getSheetAt(0);
		if (sheet == null) {
			logger.error("Excel中Sheet无效");
			throw new BaseException(ResultEnum.EXCEPTION, "Excel中Sheet无效");
		}
		// 查询线索名称
		Clue clue = this.clueMapper.selectById(clueId);
		if (null == clue) {
			throw new BaseException(ResultEnum.EXCEPTION, "线索不存在clueId:" + clueId);
		}
		writeData2Excel(wb, sheet, list, clue);
		String fileName = clue.getClueName();
		this.writeResponse(response, fileName, wb, in);
	}

	@Override
	public void exportDetail(Integer id, HttpServletResponse response) throws Exception {
		// 读取EXCEL模板
		InputStream in = FileUtils.getModel("（线索管理-线索列表-线索管理列表-查看）监督对象名称监督点监督点中文说明（范例：张三G002减刑间隔期不足） .xlsx");
		// 复制模板 写入数据
		File tempModel = FileUtils.copyModel(in);
		XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempModel));
		Sheet sheet = wb.getSheetAt(0);
		if (sheet == null) {
			logger.error("Excel中Sheet无效");
			return;
		}
		// 查询Mongo
		InfoPageDTO infoPageDTO = this.mongoService.info(id);
		// 查询明细
		TaskDetail taskDetail = this.taskDetailMapper.selectById(id);
		if (null == infoPageDTO || null == taskDetail) {
			logger.error("详情不存在！！！id：{}", id);
			return;
		}
		String reportObjectName = infoPageDTO.getReportObjectName();
		String supervisionPointName = taskDetail.getSupervisionPointName();
		writeDeatil2Excel(wb, sheet, infoPageDTO, taskDetail);
		String fileName = reportObjectName + supervisionPointName;
		this.writeResponse(response, fileName, wb, in);

	}

	private void writeDeatil2Excel(XSSFWorkbook workbook, Sheet sheet, InfoPageDTO infoPageDTO, TaskDetail taskDetail) {
		XSSFCellStyle style = this.createStyle(workbook);
		// workbook.setSheetName(0, "线索列表");
		Row row = sheet.getRow(0);
		if (row == null) {
			row = sheet.createRow(0);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		List<String> fields = Lists.newArrayList("监督对象", "监督对象名称", "监督点", "监督点中文说明");
		Set<String> reportFields = infoPageDTO.getMap().keySet();
		if (CollectionUtils.isNotEmpty(reportFields)) {
			fields.addAll(reportFields);
		}
		// 写入表头
		Row firstRow = sheet.createRow(0);
		int index = 0;
		for (String field : fields) {
			createRowAndCell(field, firstRow, cell, index, style);
			index++;
		}
		// 写入数据
		Row secondRow = sheet.createRow(1);
		createRowAndCell(taskDetail.getSupervisionObject(), secondRow, cell, 0, style);
		createRowAndCell(taskDetail.getSupervisionObjectName(), secondRow, cell, 1, style);
		createRowAndCell(taskDetail.getSupervisionPointName(), secondRow, cell, 2, style);
		createRowAndCell(taskDetail.getSupervisionPointContent(), secondRow, cell, 3, style);
		Map<String, String> map = infoPageDTO.getMap();
		if (CollectionUtils.isNotEmpty(reportFields)) {
			int i = 0;
			for (String key : reportFields) {
				createRowAndCell(map.get(key), secondRow, cell, (i + 4), style);
				i++;
			}
		}
	}

	@Override
	public void exportInfo(Integer taskLogId, Integer pointId, HttpServletResponse response) throws Exception {
		QueryClueDetailDTO queryClueDetailDTO = new QueryClueDetailDTO(1, Integer.MAX_VALUE, taskLogId, pointId);
		MongoPageResult<InfoPageDTO> page = this.mongoService.info(queryClueDetailDTO);
		List<InfoPageDTO> list = page.getData();
		// 读取EXCEL模板
		InputStream in = FileUtils.getModel("（任务管理-任务详情-监督点详情列表）监督点代号+中文说明（范例：B02减刑假释间隔异常）.xlsx");
		// 复制模板 写入数据
		File tempModel = FileUtils.copyModel(in);
		XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempModel));
		Sheet sheet = wb.getSheetAt(0);
		if (sheet == null) {
			logger.error("Excel中Sheet无效");
			throw new BaseException(ResultEnum.EXCEPTION, "Excel中Sheet无效");
		}
		// 查询监督点名称
		TaskLog taskLog = this.taskLogMapper.selectById(taskLogId);
		if (sheet == taskLog) {
			logger.error("任务日志不存在,taskLogId:{}", taskLogId);
			throw new BaseException(ResultEnum.EXCEPTION, "任务日志不存在,taskLogId:{}" + taskLogId);
		}
		List<Checkpointlist> points = this.getPoints(taskLog.getTaskId());
		Optional<Checkpointlist> option = points.stream().filter(v -> v.getId() == pointId).findFirst();
		if (option.isPresent()) {
			Checkpointlist point = option.get();
			writeInfo2Excel(wb, sheet, point, list);
			// 监督点代号+中文说明
			String fileName = point.getRule().getNumber() + point.getRule().getName();
			this.writeResponse(response, fileName, wb, in);
		}
		else {
			throw new BaseException(ResultEnum.EXCEPTION, "监督点不存在pointId:" + pointId);
		}
	}

	private void writeInfo2Excel(XSSFWorkbook workbook, Sheet sheet, Checkpointlist point, List<InfoPageDTO> list) {
		XSSFCellStyle style = this.createStyle(workbook);
		workbook.setSheetName(0, point.getName());
		Row row = sheet.getRow(0);
		if (row == null) {
			row = sheet.createRow(0);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		// 表头=监督对象+监督对象名称列+报告字段
		LinkedHashSet<String> fileds = new LinkedHashSet<String>(Lists.newArrayList("监督对象", "监督对象名称"));
		List<String> pointFieldList = point.getReportfieldlist().stream().map(Reportfieldlist::getName).collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(pointFieldList)) {
			fileds.addAll(pointFieldList);
		}
		// 此监督点无数据 写入sheet+表头
		if (CollectionUtils.isEmpty(list)) {
			// 写入第一行表头
			Iterator<String> i = fileds.iterator();
			int index = 0;
			while (i.hasNext()) {
				createRowAndCell(i.next(), row, cell, index, style);
				index++;
			}
			logger.info("监督点:{}下没有数据，跳过", point.getName());
			return;
		}
		Set<String> reportFieldList = list.get(0).getMap().keySet();
		if (CollectionUtils.isNotEmpty(reportFieldList)) {
			fileds.addAll(reportFieldList);
		}
		// 写入第一行表头
		Iterator<String> ii = fileds.iterator();
		int index1 = 0;
		while (ii.hasNext()) {
			createRowAndCell(ii.next(), row, cell, index1, style);
			index1++;
		}
		for (int i = 0; i < list.size(); i++) {
			InfoPageDTO infoPageDTO = list.get(i);
			Row other = sheet.createRow(i + 1);
			createRowAndCell(infoPageDTO.getReportObject(), other, cell, 0, style);
			createRowAndCell(infoPageDTO.getReportObjectName(), other, cell, 1, style);
			Map<String, String> map = infoPageDTO.getMap();
			Set<String> keySet = map.keySet();
			// 从第三列开始写入动态字段
			if (CollectionUtils.isNotEmpty(reportFieldList)) {
				int index = 0;
				for (String key : keySet) {
					createRowAndCell(map.get(key), other, cell, (index + 2), style);
					index++;
				}
			}
			logger.debug("已经导出数据:{}条", (i + 1));
		}
	}

	@Override
	public Set<QueryPointDTO> getPointsByTaskId(Integer taskId) {
		logger.info("getPonits taskId:{}", taskId);
		Set<QueryPointDTO> linkedHashSet = new LinkedHashSet<>();
		List<Checkpointlist> points = this.getPoints(taskId);
		// 还有历史数据有其他监督点
		//List<QueryPointDTO> oldPoints = this.taskMapper.selectPointsByTaskId(taskId);
		if (CollectionUtils.isNotEmpty(points)) {
			for (int i = 0; i < points.size(); i++) {
				Checkpointlist checkpointlist = points.get(i);
				QueryPointDTO queryPointDTO=new QueryPointDTO();
				queryPointDTO.setPointId(checkpointlist.getId());
				queryPointDTO.setPointName(checkpointlist.getName());
				linkedHashSet.add(queryPointDTO);
			}
		}
		//linkedHashSet.addAll(oldPoints);
		return linkedHashSet;
	}

	private List<Checkpointlist> getPoints(Integer taskId) {
		List<Checkpointlist> points = new ArrayList<>();
		Task task = this.taskService.getTaskById(taskId);
		if (null == task) {
			return points;
		}
		OutModelResponse<ModelInfo> out = this.modelHttpInterface.getModelInfoFull(task.getModelId());
		ModelInfo modelInfo = out.getData();
		if (out.getSuccess() && modelInfo != null) {
			points = modelInfo.getCheckpointlist();
		}
		return points;
	}

	private XSSFCellStyle createStyle(XSSFWorkbook workbook) {
		// 创建字体对象
		Font ztFont = workbook.createFont();
		ztFont.setColor(Font.COLOR_NORMAL); // 将字体设置为
		ztFont.setFontHeightInPoints((short) 10); // 将字体大小设置为10px
		ztFont.setFontName("微软雅黑"); // 将“微软雅黑”字体应用到当前单元格上
		// 创建单元格样式对象
		XSSFCellStyle style = (XSSFCellStyle) workbook.createCellStyle();
		style.setAlignment(HorizontalAlignment.CENTER);
		style.setBorderBottom(BorderStyle.THIN);
		style.setBorderLeft(BorderStyle.THIN);
		style.setBorderRight(BorderStyle.THIN);
		style.setBorderTop(BorderStyle.THIN);
		style.setFont(ztFont);
		return style;
	}

	@Override
	public void exportCollection(QueryClueDeatilDTO clueDeatilDTO, HttpServletResponse response) throws Exception {
		clueDeatilDTO.setPageNo(1);
		clueDeatilDTO.setPageSize(Integer.MAX_VALUE);

		IPage<TaskDetail> page = this.iClueCollectionService.collectionDetail(clueDeatilDTO);
		if (page == null) {
			logger.error("线索集无数据");
			throw new BaseException(ResultEnum.EXCEPTION, "线索集无数据");
		}
		List<TaskDetail> list = page.getRecords();
		// 读取EXCEL模板
		InputStream in = FileUtils.getModel("（线索管理-线索列表-线索结果列表-线索集）线索集名称 - 副本.xlsx");
		// 复制模板 写入数据
		File tempModel = FileUtils.copyModel(in);
		XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempModel));
		Sheet sheet = wb.getSheetAt(0);
		if (sheet == null) {
			logger.error("Excel中Sheet无效");
			throw new BaseException(ResultEnum.EXCEPTION, "Excel中Sheet无效");
		}
		// 查询线索集名称
		ClueCollection clueCollection = this.clueCollectionMapper.selectById(clueDeatilDTO.getCollectionId());
		if (null == clueCollection) {
			throw new BaseException(ResultEnum.EXCEPTION, "线索集不存在collectionId:" + clueDeatilDTO.getCollectionId());
		}
		writeCollectionData2Excel(wb, sheet, list, clueCollection);
		String fileName = clueCollection.getName();
		this.writeResponse(response, fileName, wb, in);
	}

	private void writeResponse(HttpServletResponse response, String fileName, XSSFWorkbook wb, InputStream in) throws Exception {
		// 设置文件头
		response.setContentType("application/octet-stream");
		String excelName = fileName + ".xlsx";
		response.addHeader("Content-Disposition", "attachment;fileName=" + new String(excelName.getBytes("UTF-8"), "ISO-8859-1"));
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		wb.write(bos);
		byte[] bytes = bos.toByteArray();
		response.getOutputStream().write(bytes);
		IOUtils.closeQuietly(in);
		IOUtils.closeQuietly(bos);
		logger.info("Excel中数据导出成功");
	}

	private void writeCollectionData2Excel(XSSFWorkbook workbook, Sheet sheet, List<TaskDetail> list, ClueCollection clueCollection) {
		XSSFCellStyle style = this.createStyle(workbook);
		workbook.setSheetName(0, clueCollection.getName());
		Row row = sheet.getRow(1);
		if (row == null) {
			row = sheet.createRow(1);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		for (int i = 0; i < list.size(); i++) {
			TaskDetail vo = list.get(i);
			Row other = sheet.createRow(i + 1);
			createRowAndCell(vo.getSupervisionObject(), other, cell, 0, style);
			createRowAndCell(vo.getSupervisionObjectName(), other, cell, 1, style);
			createRowAndCell(vo.getSupervisionPointName(), other, cell, 2, style);
			createRowAndCell(vo.getSupervisionPointContent(), other, cell, 3, style);
			createRowAndCell(WeightEnum.getValue(vo.getWeight()), other, cell, 4, style);
			logger.debug("已经导出数据:{}条", (i + 1));
		}
		// 线索集里涉及所有的监督点id集合
		LinkedHashSet<Checkpointlist> allPoints = new LinkedHashSet<>();
		// 所有的TaskId集合
		Set<Integer> taskIds = list.stream().map(TaskDetail::getTaskId).collect(Collectors.toSet());
		taskIds.forEach(taskId -> {
			List<Checkpointlist> points = this.getPoints(taskId);
			if (CollectionUtils.isNotEmpty(points)) {
				allPoints.addAll(points);
			}
		});
		// 数据按照监督点id分组
		Map<Integer, List<TaskDetail>> map = list.stream().collect(Collectors.groupingBy(TaskDetail::getSupervisionPointId));
		// 写入监督点sheet
		for (Checkpointlist point : allPoints) {
			List<TaskDetail> data = map.getOrDefault(point.getId(), new ArrayList<>());
			this.writeSupevisePonits(workbook, point, data);
		}
	}

	// 分监督点写入数据
	private void writeSupevisePonits(XSSFWorkbook workbook, Checkpointlist point, List<TaskDetail> data) {
		XSSFCellStyle style = this.createStyle(workbook);
		XSSFSheet sheet = workbook.createSheet(point.getRule().getNumber() + point.getName());
		Row row = sheet.getRow(0);
		if (row == null) {
			row = sheet.createRow(0);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		// 表头=监督对象+监督对象名称列+报告字段
		LinkedHashSet<String> fileds = new LinkedHashSet<String>(Lists.newArrayList("监督对象", "监督对象名称"));
		List<String> pointFieldList = point.getReportfieldlist().stream().map(Reportfieldlist::getName).collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(pointFieldList)) {
			fileds.addAll(pointFieldList);
		}
		if (CollectionUtils.isEmpty(data)) {
			// 此监督点无数据 写入第一行表头
			Iterator<String> i = fileds.iterator();
			int index = 0;
			while (i.hasNext()) {
				createRowAndCell(i.next(), row, cell, index, style);
				index++;
			}
			logger.info("监督点:{}下没有数据，跳过", point.getName());
			return;
		}
		// 根据多个taskLogId pointId获取Mongo数据 这里是夸任务下载
		List<Integer> ids = data.stream().map(TaskDetail::getId).collect(Collectors.toList());
		Set<Integer> taskLogIds = data.stream().map(TaskDetail::getTaskLogId).collect(Collectors.toSet());
		QueryClueDetailDTO queryClueDetailDTO = new QueryClueDetailDTO(1, Integer.MAX_VALUE, taskLogIds, point.getId(), ids);
		MongoPageResult<InfoPageDTO> mongoPageResult = this.mongoService.info(queryClueDetailDTO);
		if (mongoPageResult.getTotal() == null || mongoPageResult.getTotal() <= 0L) {
			// 此监督点无数据 写入第一行表头
			Iterator<String> i = fileds.iterator();
			int index = 0;
			while (i.hasNext()) {
				createRowAndCell(i.next(), row, cell, index, style);
				index++;
			}
			logger.info("监督点:{}下没有数据，跳过", point.getName());
			return;
		}
		List<InfoPageDTO> mongoDataList = mongoPageResult.getData();
		// mongo数据key集合+固定表头+报告字段
		List<Set<String>> reportFieldList = mongoDataList.stream().map(InfoPageDTO::getMap).map(Map::keySet).collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(reportFieldList)) {
			reportFieldList.forEach(v -> {
				fileds.addAll(v);
			});
		}
		// 写入第一行表头
		Iterator<String> ii = fileds.iterator();
		int index1 = 0;
		while (ii.hasNext()) {
			String fieldName = ii.next();
			createRowAndCell(fieldName, row, cell, index1, style);
			index1++;
		}
		List<String> allfileds = new ArrayList<>(fileds);
		// 写入数据
		for (int i = 0; i < mongoDataList.size(); i++) {
			InfoPageDTO infoPageDTO = mongoDataList.get(i);
			Map<String, String> map = infoPageDTO.getMap();
			Row other = sheet.createRow(i + 1);
			createRowAndCell(infoPageDTO.getReportObject(), other, cell, 0, style);
			createRowAndCell(infoPageDTO.getReportObjectName(), other, cell, 1, style);
			// 从第三列开始写入动态字段
			if (CollectionUtils.size(fileds) <= 2) {
				continue;
			}
			for (int cellNum = 2; cellNum < fileds.size(); cellNum++) {
				String fieldName = allfileds.get(cellNum);
				// 数据中不存在此列 写入空
				createRowAndCell(map.getOrDefault(fieldName, ""), other, cell, cellNum, style);
			}
			logger.debug("监督点pointName:{}已经写入数据:{}条", point.getName(), (i + 1));
		}
	}

	@Override
	public void exportOverview(ManageDTO manageDTO, HttpServletResponse response) throws Exception {
		manageDTO.setPageNo(1);
		manageDTO.setPageSize(Integer.MAX_VALUE);
		IPage<ManageTaskDetailDTO> page = this.iCluePushService.listInquisitorManage(manageDTO, false);
		List<ManageTaskDetailDTO> list = page.getRecords();
		// 读取EXCEL模板
		InputStream in = FileUtils.getModel("（线索管理-线索列表-线索结果列表-线索集）线索集名称 - 副本.xlsx");
		// 复制模板 写入数据
		File tempModel = FileUtils.copyModel(in);
		XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempModel));
		Sheet sheet = wb.getSheetAt(0);
		if (sheet == null) {
			logger.error("Excel中Sheet无效");
			throw new BaseException(ResultEnum.EXCEPTION, "Excel中Sheet无效");
		}
		// 查询线索集名称
		CluePush cluePush = this.cluePushMapper.selectById(manageDTO.getPushId());
		if (null == cluePush) {
			throw new BaseException(ResultEnum.EXCEPTION, "线索不存在PushId:" + manageDTO.getPushId());
		}
		writeOverviewData2Excel(wb, sheet, list, cluePush.getName());
		this.writeResponse(response, cluePush.getName(), wb, in);
	}

	@Override
	public CommonResponse check(Integer modelId) {
		LambdaQueryWrapper<Task> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(Task::getModelId, modelId);
		Long count = this.taskMapper.selectCount(lambdaQueryWrapper);
		return count > 0L ? CommonResponse.failed(ResultEnum.MODEL_IS_RELATED_TASK) : CommonResponse.success();
	}

	private void writeOverviewData2Excel(XSSFWorkbook workbook, Sheet sheet, List<ManageTaskDetailDTO> list,String sheetName) {
		XSSFCellStyle style = this.createStyle(workbook);
		workbook.setSheetName(0, sheetName);
		Row row = sheet.getRow(1);
		if (row == null) {
			row = sheet.createRow(1);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		for (int i = 0; i < list.size(); i++) {
			ManageTaskDetailDTO vo = list.get(i);
			Row other = sheet.createRow(i + 1);
			createRowAndCell(vo.getSupervisionObject(), other, cell, 0, style);
			createRowAndCell(vo.getSupervisionObjectName(), other, cell, 1, style);
			createRowAndCell(vo.getSupervisionPointName(), other, cell, 2, style);
			createRowAndCell(vo.getSupervisionPointContent(), other, cell, 3, style);
			createRowAndCell(WeightEnum.getValue(vo.getWeight()), other, cell, 4, style);
			logger.debug("已经导出数据:{}条", (i + 1));
		}
		// 线索集里涉及所有的监督点id集合
		LinkedHashSet<Checkpointlist> allPoints = new LinkedHashSet<>();
		// 所有的TaskId集合
		Set<Integer> taskIds = list.stream().map(ManageTaskDetailDTO::getTaskId).collect(Collectors.toSet());
		taskIds.forEach(taskId -> {
			List<Checkpointlist> points = this.getPoints(taskId);
			if (CollectionUtils.isNotEmpty(points)) {
				allPoints.addAll(points);
			}
		});
		// 数据按照监督点id分组
		Map<Integer, List<ManageTaskDetailDTO>> map = list.stream().collect(Collectors.groupingBy(ManageTaskDetailDTO::getSupervisionPointId));
		// 写入监督点sheet
		for (Checkpointlist point : allPoints) {
			List<ManageTaskDetailDTO> data = map.getOrDefault(point.getId(), new ArrayList<>());
			if (CollectionUtils.isEmpty(data)) {
				logger.info("监督点:{}下没有数据，跳过", point.getName());
				continue;
			}
			XSSFSheet otherSheet = workbook.createSheet(point.getRule().getNumber() + point.getName());
			this.writeOverviewPonits(workbook, point, data,otherSheet);
		}
	}

	// 分监督点写入数据
	private void writeOverviewPonits(XSSFWorkbook workbook, Checkpointlist point, List<ManageTaskDetailDTO> data,Sheet sheet) {
		XSSFCellStyle style = this.createStyle(workbook);
		Row row = sheet.getRow(0);
		if (row == null) {
			row = sheet.createRow(0);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		// 表头=监督对象+监督对象名称列+报告字段
		LinkedHashSet<String> fileds = new LinkedHashSet<String>(Lists.newArrayList("监督对象", "监督对象名称"));
		List<String> pointFieldList = point.getReportfieldlist().stream().map(Reportfieldlist::getName).collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(pointFieldList)) {
			fileds.addAll(pointFieldList);
		}
		// 根据多个taskLogId pointId获取Mongo数据 这里是夸任务下载
		List<Integer> ids = data.stream().map(ManageTaskDetailDTO::getId).collect(Collectors.toList());
		Set<Integer> taskLogIds = data.stream().map(ManageTaskDetailDTO::getTaskLogId).collect(Collectors.toSet());
		QueryClueDetailDTO queryClueDetailDTO = new QueryClueDetailDTO(1, Integer.MAX_VALUE, taskLogIds, point.getId(), ids);
		MongoPageResult<InfoPageDTO> mongoPageResult = this.mongoService.info(queryClueDetailDTO);
		if (mongoPageResult.getTotal() == null || mongoPageResult.getTotal() <= 0L) {
			// 此监督点无数据 写入第一行表头
			Iterator<String> i = fileds.iterator();
			int index = 0;
			while (i.hasNext()) {
				createRowAndCell(i.next(), row, cell, index, style);
				index++;
			}
			logger.info("监督点:{}下没有数据，跳过", point.getName());
			return;
		}
		List<InfoPageDTO> mongoDataList = mongoPageResult.getData();
		// mongo数据key集合+固定表头+报告字段
		List<Set<String>> reportFieldList = mongoDataList.stream().map(InfoPageDTO::getMap).map(Map::keySet).collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(reportFieldList)) {
			reportFieldList.forEach(v -> {
				fileds.addAll(v);
			});
		}
		// 写入第一行表头
		Iterator<String> ii = fileds.iterator();
		int index1 = 0;
		while (ii.hasNext()) {
			String fieldName = ii.next();
			createRowAndCell(fieldName, row, cell, index1, style);
			index1++;
		}
		List<String> allfileds = new ArrayList<>(fileds);
		// 写入数据
		for (int i = 0; i < mongoDataList.size(); i++) {
			InfoPageDTO infoPageDTO = mongoDataList.get(i);
			Map<String, String> map = infoPageDTO.getMap();
			Row other = sheet.createRow(i + 1);
			createRowAndCell(infoPageDTO.getReportObject(), other, cell, 0, style);
			createRowAndCell(infoPageDTO.getReportObjectName(), other, cell, 1, style);
			// 从第三列开始写入动态字段
			if (CollectionUtils.size(fileds) <= 2) {
				continue;
			}
			for (int cellNum = 2; cellNum < fileds.size(); cellNum++) {
				String fieldName = allfileds.get(cellNum);
				// 数据中不存在此列 写入空
				createRowAndCell(map.getOrDefault(fieldName, ""), other, cell, cellNum, style);
			}
			logger.debug("监督点pointName:{}已经写入数据:{}条", point.getName(), (i + 1));
		}
	}

	@Override
	public void exportTaskLogDetail(TaskManageListBo taskManageListBo, HttpServletResponse response) throws Exception {
		    taskManageListBo.setPageNo(1);
		    taskManageListBo.setPageSize(Integer.MAX_VALUE);
			IPage<TaskDetail> page = taskService.queryTaskDetailList(taskManageListBo);
			List<TaskDetail> list = page.getRecords();
			// 读取EXCEL模板
			InputStream in = FileUtils.getModel("（任务管理-任务详情）任务名称（范例：减刑假释长春第一批数据20221020.1022）.xlsx");
			// 复制模板 写入数据
			File tempModel = FileUtils.copyModel(in);
			XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempModel));
			Sheet sheet = wb.getSheetAt(0);
			if (sheet == null) {
				logger.error("Excel中Sheet无效");
				throw new BaseException(ResultEnum.EXCEPTION, "Excel中Sheet无效");
			}
			// 查询XXX名称
			TaskLog taskLog = this.taskLogMapper.selectById(taskManageListBo.getId());
			if (null == taskLog) {
				throw new BaseException(ResultEnum.EXCEPTION, "任务日志不存在clueId:" + taskManageListBo.getId());
			}
			Task task = this.taskMapper.selectById(taskLog.getTaskId());
			if (null == task) {
				throw new BaseException(ResultEnum.EXCEPTION, "任务不存在taskId:" + taskLog.getTaskId());
			}
			writeDetail2Excel(wb, sheet, list,task);
			String fileName = task.getTaskName();
			this.writeResponse(response, fileName, wb, in);
	}
	
	private void writeDetail2Excel(XSSFWorkbook workbook, Sheet sheet, List<TaskDetail> list,Task task) {
		XSSFCellStyle style = this.createStyle(workbook);
		workbook.setSheetName(0, "线索列表");
		Row row = sheet.getRow(1);
		if (row == null) {
			row = sheet.createRow(1);
		}
		Cell cell = row.getCell(0);
		if (cell == null) {
			cell = row.createCell(0);
		}
		for (int i = 0; i < list.size(); i++) {
			TaskDetail vo = list.get(i);
			Row other = sheet.createRow(i + 1);
			createRowAndCell(vo.getSupervisionObject(), other, cell, 0, style);
			createRowAndCell(vo.getSupervisionObjectName(), other, cell, 1, style);
			createRowAndCell(vo.getSupervisionPointName(), other, cell, 2, style);
			createRowAndCell(vo.getSupervisionPointContent(), other, cell, 3, style);
			createRowAndCell(WeightEnum.getValue(vo.getWeight()), other, cell, 4, style);
			logger.debug("已经导出数据:{}条", (i + 1));
		}
		// 获取监督点
		List<Checkpointlist> points = this.getPoints(task.getId());
		if (CollectionUtils.isEmpty(points)) {
			return;
		}
		// 数据按照监督点id分组
		Map<Integer, List<TaskDetail>> map = list.stream().collect(Collectors.groupingBy(TaskDetail::getSupervisionPointId));
		// 写入监督点sheet
		for (Checkpointlist point : points) {
			List<TaskDetail> data = map.getOrDefault(point.getId(), new ArrayList<>());
			this.writeSupevisePonits(workbook, point, data);
		}
	}

	@Override
	public Object getPonitsByPushId(Integer pushId) {
		CluePush cluePush = this.cluePushMapper.selectById(pushId);
		if (null == cluePush) {
			throw new BaseException(ResultEnum.EXCEPTION, "推送线索不存在,pushId" + pushId);
		}
		ManageDTO manageDTO = new ManageDTO(1, Integer.MAX_VALUE, pushId, "");
		JSONArray jSONArray = new JSONArray();
		// 兜底数据
		Map<Integer, String> map = new HashMap<>();
		IPage<ManageTaskDetailDTO> page = this.iCluePushService.listInquisitorManage(manageDTO, false);
		if (null == page || CollectionUtils.sizeIsEmpty(page.getRecords())) {
			return jSONArray;
		}
		// 所有任务id集合
		List<Integer> taskIds = page.getRecords().stream().map(ManageTaskDetailDTO::getTaskId).collect(Collectors.toList());

		LinkedHashSet<Integer> taskIdSet = new LinkedHashSet<Integer>(taskIds);
		List<Task> tasks = this.taskMapper.selectBatchIds(taskIdSet);
		if (CollectionUtils.sizeIsEmpty(tasks)) {
			return jSONArray;
		}
		// 所有任务模型id集合
		Set<Integer> modelIds = tasks.stream().filter(v -> v.getModelId() != null && v.getModelId() > 0).map(Task::getModelId).collect(Collectors.toSet());
		modelIds.forEach(modelId -> {
			// 每个模型监督点涉及的监督点
			OutModelResponse<ModelInfo> out = this.modelHttpInterface.getModelInfoFull(modelId);
			if (null != out && out.getSuccess() && null != out.getData()) {
				ModelInfo modelInfo = out.getData();
				List<Checkpointlist> points = modelInfo.getCheckpointlist();
				if (CollectionUtils.isNotEmpty(points)) {
					for (int i = 0; i < points.size(); i++) {
						Checkpointlist checkpointlist = points.get(i);
						JSONObject data = new JSONObject();
						data.put("pointId", checkpointlist.getId());
						data.put("pointName", checkpointlist.getRule().getNumber() + checkpointlist.getName());
						jSONArray.add(data);
					}
				}
			}
		});
		// 兜底方案 模型被禁用了
		if (jSONArray.size() == 0) {
			map = page.getRecords().stream()
			        .collect(Collectors.toMap(className -> className.getSupervisionPointId(), className -> className.getSupervisionPointId() + className.getSupervisionPointName(), (v1, v2) -> {
				        return v2;
			        }));

			if (MapUtils.isNotEmpty(map)) {
				Set<Integer> set=map.keySet();
				for(Integer key:set) {
					JSONObject data = new JSONObject();
					data.put("pointId", key);
					data.put("pointName", map.get(key));
					jSONArray.add(data);
				}
			}
		}
		return jSONArray;
	}

	@Override
	public void exportChakan(ManageDTO manageDTO, HttpServletResponse response) throws Exception {
		manageDTO.setPageNo(1);
		manageDTO.setPageSize(Integer.MAX_VALUE);
		IPage<ManageTaskDetailDTO> page = this.iCluePushService.listInquisitorManage(manageDTO, false);
		List<ManageTaskDetailDTO> list = page.getRecords();
		if(CollectionUtils.isEmpty(list)){
			logger.error("该监督点下无数据无法导出");
			throw new BaseException(ResultEnum.EXCEPTION, "该监督点下无数据无法导出，pointId:"+manageDTO.getPointId());
		}
		// 读取EXCEL模板
		InputStream in = FileUtils.getModel("（任务管理-线索管理-单个线索集检察官-监督点详情）监督点代号+中文说明（范例：G40041减刑假释间隔异常）.xlsx");
		// 复制模板 写入数据
		File tempModel = FileUtils.copyModel(in);
		XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempModel));
		Sheet sheet = wb.getSheetAt(0);
		if (sheet == null) {
			logger.error("Excel中Sheet无效");
			throw new BaseException(ResultEnum.EXCEPTION, "Excel中Sheet无效");
		}
		// 查询推送名称
		CluePush cluePush = this.cluePushMapper.selectById(manageDTO.getPushId());
		if (null == cluePush) {
			throw new BaseException(ResultEnum.EXCEPTION, "线索不存在PushId:" + manageDTO.getPushId());
		}
		writeChakanData2Excel(wb, sheet, list, manageDTO);
		this.writeResponse(response, cluePush.getName(), wb, in);
	}
	
	private void writeChakanData2Excel(XSSFWorkbook workbook, Sheet sheet, List<ManageTaskDetailDTO> list, ManageDTO manageDTO) {
		List<Checkpointlist> points = this.getPoints(list.get(0).getTaskId());
		Object o=getPonitsByPushId(manageDTO.getPushId());
		Optional<Checkpointlist> optional = points.stream().filter(v -> v.getId() == manageDTO.getPointId()).findFirst();
		if (optional.isPresent()) {
			Checkpointlist point = optional.get();
			this.writeOverviewPonits(workbook, point, list,sheet);
			workbook.setSheetName(0, point.getRule().getNumber()+point.getName());
		}
	}
}
